package vip.xiaomaoxiaoke.joinbymemory.support;


import vip.xiaomaoxiaoke.joinbymemory.JoinItemExecutor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;

import java.util.List;
import java.util.Map;
import java.util.Objects;

import static java.util.stream.Collectors.groupingBy;
import static java.util.stream.Collectors.toList;

/**
 * 抽象类执行器
 * */
@Slf4j
abstract class AbstractJoinItemExecutor<SOURCE_DATA, JOIN_KEY, JOIN_DATA, JOIN_RESULT> implements JoinItemExecutor<SOURCE_DATA> {

    /**
     * 获取源数据的key
     * */
    protected abstract JOIN_KEY createJoinKeyFromSourceData(SOURCE_DATA data);


    /**
     * 传如主见的key后获取关联数据
     * */
    protected abstract List<JOIN_DATA> getJoinDataByJoinKeys(List<JOIN_KEY> joinKeys);

    /**
     * 获取关联数据的key值
     * */

    protected abstract JOIN_KEY createJoinKeyFromJoinData(JOIN_DATA joinData);


    protected abstract String mainkeys(SOURCE_DATA joinData);
    protected abstract String outkeys(JOIN_DATA joinData);


    /**
     * 结果转换器
     * */
    protected abstract JOIN_RESULT convertToResult(JOIN_DATA joinData);

    /**
     * 有匹配数据是复制数据的方法
     * */
    protected abstract void onFound(SOURCE_DATA data, List<JOIN_RESULT> JoinResults);

    /***
     * 没有匹配数据时赋值数据的方法
     * */
    protected abstract void onNotFound(SOURCE_DATA data, String joinKey);

    /**
     * 执行方法
     * */
    @Override
    public void execute(List<SOURCE_DATA> sourceDatas) {
        // 从源数据中提取 JoinKey
        List<JOIN_KEY> joinKeys = sourceDatas.stream()
                .filter(Objects::nonNull)
                .map(this::createJoinKeyFromSourceData)
                .filter(Objects::nonNull)
                .distinct()
                .collect(toList());
        log.debug("get join key {} from source data {}", joinKeys, sourceDatas);
        // 根据 JoinKey 获取 JoinData
        List<JOIN_DATA> allJoinDatas = getJoinDataByJoinKeys(joinKeys);
        log.debug("get join data {} by join key {}", allJoinDatas, joinKeys);
        if (allJoinDatas == null || allJoinDatas.size() == 0) return;
        // 将 JoinData 以 Map 形式进行组织
        Map<String, List<JOIN_DATA>> joinDataMap = allJoinDatas.stream()
                .filter(Objects::nonNull)
                .collect(groupingBy(e->String.valueOf(outkeys(e))));
        log.debug("group by join key, result is {}", joinDataMap);

            // 处理每一条 SourceData
        for (SOURCE_DATA data : sourceDatas){
            // 从 SourceData 中 获取 JoinKey
            String joinKey = mainkeys(data);
            if (joinKey == null){
                log.warn("join key from join data {} is null", data);
                continue;
            }
            // 根据 JoinKey 获取 JoinData
            List<JOIN_DATA> joinDatasByKey = joinDataMap.get(String.valueOf(joinKey));
            if (CollectionUtils.isNotEmpty(joinDatasByKey)){
                // 获取到 JoinData， 转换为 JoinResult，进行数据写回
                List<JOIN_RESULT> joinResults = joinDatasByKey.stream()
                        .filter(Objects::nonNull)
                        .map(joinData -> convertToResult(joinData))
                        .collect(toList());

                log.debug("success to convert join data {} to join result {}", joinDatasByKey, joinResults);
                onFound(data, joinResults);
                log.debug("success to write join result {} to source data {}", joinResults, data);
            }else {
                log.warn("join data lost by join key {} for source data {}", joinKey, data);
                // 为获取到 JoinData，进行 notFound 回调
                onNotFound(data, joinKey);
            }
        }
    }
}
